package socket;

import dao.BaseDao;
import entity.ChessUser;
import message.BaseMessage;
import model.RoomInfo;
import service.ChessUserService;
import service.Impl.ChessUserServiceImpl;
import thread.ClientAtServerThread;
import thread.WaitClientConnectThread;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * 服务器类，单例模式.
 *
 * @author 张天羿
 */
public class ChessServer {
    private static ChessServer instance;

    private ChessServer() {
    }

    public static ChessServer getInstance() {

        if (instance == null) {
            instance = new ChessServer();
            instance.resetRooms();
            BaseDao.getConnection();
        }
        return instance;
    }

    private List<RoomInfo> rooms = new ArrayList<RoomInfo>();
    public static List<ClientAtServerThread> clientAtServerThreadList = new LinkedList<ClientAtServerThread>();
    ServerSocket server = null;
    private ChessUserService chessUserService = new ChessUserServiceImpl();

    public ChessUserService getChessUserService() {
        return chessUserService;
    }

    public List<RoomInfo> getRooms() {
        return rooms;
    }

    /**
     * 启动服务器，启动线程监听客户端连接
     *
     * @return 返回服务器是否启动
     */
    public boolean startListen() {
        try {
            server = new ServerSocket(8008);
            System.out.println("服务器启动成功");
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return false;
        }
        new WaitClientConnectThread(server).start();
        return true;
    }

    /**
     * 服务器发送报文.
     *
     * @param baseMessage  报文内容
     * @param targetClient 目标客户端
     */
    public void sendMessage(BaseMessage baseMessage, Socket targetClient) {
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(targetClient.getOutputStream());
            objectOutputStream.writeObject(baseMessage);
            System.out.println("发送报文" + baseMessage);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println("给" + targetClient + "发送数据失败");
        }
    }

    /**
     * 在报文中sendToServer方法中调用,给相应客户端发送相应的报文.
     *
     * @param baseMessage  应该发送的报文
     * @param targetClient 相应的客户端
     */
    public void sendMsgToClient(BaseMessage baseMessage, Socket targetClient) {
        for (ClientAtServerThread clientAtServerThread : clientAtServerThreadList) {
            if (clientAtServerThread.getClient() == targetClient) {
                this.sendMessage(baseMessage, targetClient);
                return;
            }
        }
    }

    /**
     * 将用户对象和与之匹配的线程进行绑定.
     *
     * @param chessUser
     * @param client
     */
    public void bindUsername(ChessUser chessUser, Socket client) {
        for (ClientAtServerThread clientAtServerThread : clientAtServerThreadList) {
            if (clientAtServerThread.getClient() == client) {
                clientAtServerThread.setUser(chessUser);
                return;
            }
        }
    }

    /**
     * 判断用户是否已登录.
     *
     * @param chessUser
     * @return 用户是否已登录
     */
    public boolean logged(ChessUser chessUser) {
        for (ClientAtServerThread clientAtServerThread : clientAtServerThreadList) {
            if (chessUser.equals(clientAtServerThread.getUser())) {
                System.out.println(chessUser.getName() + "   判断相等   " + clientAtServerThread.getUser().getName());
                return false;
            }
        }
        return true;
    }

    /**
     * 获得当前在线用户的集合数组
     *
     * @return
     */
    public List<ChessUser> getUserList() {
        List<ChessUser> list = new ArrayList<ChessUser>();
        for (ClientAtServerThread clientAtServerThread : clientAtServerThreadList) {
            if (clientAtServerThread.getUser() != null)
                list.add(clientAtServerThread.getUser());
        }
        return list;
    }

    /**
     * 服务器向所有在线客户端发送报文.
     *
     * @param baseMessage
     */
    public void sendMsgToAll(BaseMessage baseMessage) {
        for (ClientAtServerThread clientAtServerThread : clientAtServerThreadList) {
            this.sendMessage(baseMessage, clientAtServerThread.getClient());
        }
    }


    /**
     * 发送报文给指定User的客户端.
     *
     * @param baseMessage
     * @param user
     */
    public void sendMsgToClient(BaseMessage baseMessage, ChessUser user) {
        for (ClientAtServerThread clientAtServerThread : clientAtServerThreadList) {
            if (clientAtServerThread.getUser().getName().equals(user.getName())) {
                this.sendMessage(baseMessage, clientAtServerThread.getClient());
                return;
            }
        }
    }

    /**
     * 服务器启动时重置房间列表信息.
     */
    private void resetRooms() {
        rooms.clear();
        for (int i = 0; i < 12; i++) {
            RoomInfo r = new RoomInfo(i, null, null, RoomInfo.NONE);
            rooms.add(r);
        }
    }

    public static void main(String[] args) {
        ChessServer.getInstance().startListen();
    }
}
